﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.Objects.DataClasses;
using Fujitsu.JiraAnalysis.JiraRPC;
using Fujitsu.JiraAnalysis.DAL;
using Fujitsu.JiraAnalysis.Common;
using Fujitsu.JiraAnalysis.TrackingSystemAdapter;

namespace Fujitsu.JiraAnalysis.ReplicationService.Synchronize
{
    class IssueWorklogUpdate : DbObjectUpdateBase
    {
        WorklogStorage worklogStorage = new WorklogStorage();

        public IssueWorklogUpdate(ITrackSystemInfo adapter, int issueId, string issueKey, string issueName)
            : base(adapter, issueId, issueKey, issueName)
        { }

        #region Abstract
        protected override IEnumerable<AbstractRemoteEntity> GetRemoteEntities(string issueKey)
        {
            return Adapter.GetWorkLogs(issueKey);
        }

        protected override EntityObject FindMatchInDb(int issueId, AbstractRemoteEntity remoteEntity)
        {
            return worklogStorage.GetWorklogForIssue(issueId, (remoteEntity as RemoteWorklog).id);
        }

        protected override void UpdateEntityObject(EntityObject dbEntityObject, AbstractRemoteEntity remoteEntity)
        {
            var dbWorklog = dbEntityObject as Worklog;
            var jiraWorklog = remoteEntity as RemoteWorklog;

            logInfo.AppendLine(string.Format("Issue '{0}' -> updated WorklogID '{1}', updated fields are", Key, dbWorklog.ID));

            var isIssueEdited = UpdateWorklogAuthor(dbWorklog, jiraWorklog)
                | UpdateWorklogUpdateAuthor(dbWorklog, jiraWorklog)
                | UpdateEntityObjectField<string>(dbWorklog, "Body", dbWorklog.Body, jiraWorklog.comment)
                | UpdateEntityObjectField<DateTime?>(dbWorklog, "Created", dbWorklog.Created, jiraWorklog.created)
                | UpdateEntityObjectField<DateTime?>(dbWorklog, "Updated", dbWorklog.Updated, jiraWorklog.updated)
                | UpdateEntityObjectField<DateTime?>(dbWorklog, "StartDate", dbWorklog.StartDate, jiraWorklog.startDate)
                | UpdateEntityObjectField<decimal>(dbWorklog, "TimeWorked", dbWorklog.TimeWorked, (decimal)jiraWorklog.timeSpentInSeconds);

            if (isIssueEdited)
            {
                worklogStorage.UpdateWorklog(dbWorklog);
                EventLogger.CreateInstance(eventLog).LogWrite(logInfo.ToString());
            }

            logInfo.Clear();
        }

        protected override void AddEntityObjectToDb(int issueId, AbstractRemoteEntity remoteEntityToBeAdded)
        {
            var jiraWorklog = remoteEntityToBeAdded as RemoteWorklog;

            var dbWorklog = new Worklog { JiraWorklogID = jiraWorklog.id, IssueID = issueId};

            var worklogAuthor = Adapter.GetUser(jiraWorklog.author);
            dbWorklog.AuthorID = userStorage.AddOrUpdateUser(worklogAuthor.name, worklogAuthor.name, worklogAuthor.fullname);

            dbWorklog.Body = jiraWorklog.comment;
            dbWorklog.Created = jiraWorklog.created;

            var worklogUpdateAuthor = Adapter.GetUser(jiraWorklog.updateAuthor);
            dbWorklog.UpdateAuthorID = userStorage.AddOrUpdateUser(worklogUpdateAuthor.name, worklogUpdateAuthor.name, worklogUpdateAuthor.fullname);

            dbWorklog.Updated = jiraWorklog.updated;
            dbWorklog.StartDate = jiraWorklog.startDate;

            dbWorklog.TimeWorked = (decimal)jiraWorklog.timeSpentInSeconds;

            if (worklogStorage.AddWorklog(dbWorklog) != null)
            {
                EventLogger.CreateInstance(eventLog).LogWrite(string.Format("Added worklog '{0}' to issue '{1}'", dbWorklog.ID, Key));
            }
        }

        protected override IEnumerable<int> GetToBeDeletedList(int issueId, IEnumerable<AbstractRemoteEntity> remoteEntities)
        {
            var jiraWorklogIds = remoteEntities.Select(w => (w as RemoteWorklog).id).ToList();
            return worklogStorage.GetWorklogIdsToBeDeleted(issueId, jiraWorklogIds);
        }

        protected override void DeleteEntityObject(int dbEntityObjectId)
        {
            worklogStorage.DeleteWorklog(dbEntityObjectId);
        }
        #endregion

        private bool UpdateWorklogAuthor(Worklog dbWorklog, RemoteWorklog jiraWorklog)
        {
            var result = UpdateRelatedUser(dbWorklog.AuthorID, jiraWorklog.author);
            return result != null && UpdateEntityObjectField<int>(dbWorklog, "AuthorID", dbWorklog.AuthorID, result.Value);
        }

        private bool UpdateWorklogUpdateAuthor(Worklog dbWorklog, RemoteWorklog jiraWorklog)
        {
            var result = UpdateRelatedUser(dbWorklog.UpdateAuthorID, jiraWorklog.updateAuthor);
            return result != null && UpdateEntityObjectField<int>(dbWorklog, "UpdateAuthorID", dbWorklog.UpdateAuthorID, result.Value);
        }        
    }
}
